#pragma once
#include "net.hpp"
//根据信息类型的不同调用不同响应方法进行处理的功能
namespace BRpc
{
    //利用父类指针指向基类指针可以调用函数来解决容器无法储存多种类型而产生的问题 
    class CallBack
    {
    public:
        using ptr=std::shared_ptr<CallBack>;
        virtual void onMessage(const BaseConnection::ptr& conn,BaseMessage::ptr msg)=0;
    };
    template<typename T>
    class CallBackT:public CallBack
    {
    public:
        using ptr = std::shared_ptr<CallBackT<T>>;
        using MessageCallBack=std::function<void(const BaseConnection::ptr &,std::shared_ptr<T> &)>;
    public:
        CallBackT(const MessageCallBack& handler): _handler(handler){}
        void onMessage(const BaseConnection::ptr& conn,BaseMessage::ptr msg)   override
        {
            auto type_msg=std::dynamic_pointer_cast<T>(msg);
            _handler(conn,type_msg);
        }
    private:
        MessageCallBack _handler;
    };

    class Dispatcher
    {
    public:
        using ptr=std::shared_ptr<Dispatcher>;
    public:
        template<typename T>
        void registerHandler(MType mtype,const typename CallBackT<T>::MessageCallBack &handler)//很巧妙的做到了一个信息类型的回调函数可以处理多种类型的信息
        {
            //注册处理方法
            std::unique_lock<std::mutex> lock(_mutex);
            auto cb=std::make_shared<CallBackT<T>>(handler);
            _handlers.insert(make_pair(mtype,cb));
        }
        void onMessage(const BaseConnection::ptr& conn,BaseMessage::ptr msg)
        {
            //找到对应信息类型的处理方法函数然后调用
            std::unique_lock<std::mutex> lock(_mutex);
            auto it=_handlers.find(msg->mtype());
            if(it!=_handlers.end())
            {
                it->second->onMessage(conn,msg);
                return;
            }
            //未知类型的消息
            ELOG("收到了未知类型的消息%d",msg->mtype());
            conn->shutdown();
        }
    private:
        std::mutex _mutex;
        std::unordered_map<MType,CallBack::ptr> _handlers;
    };
}